HJS

조건부 타입 (Conditional Types)

조건부 타입은 T extends U ? X : Y 형태로 사용되며, 타입 TU의 서브타입이면 X, 아니면 Y를 반환하는 타입입니다.
이는 JavaScript의 삼항 연산자(? : )와 유사한 역할을 하며, 제네릭과 함께 사용하여 동적인 타입 변환이 가능합니다.

1️⃣ 장점

2️⃣ 예시

🔹 기본적인 조건부 타입

조건부 타입은 T extends U ? X : Y와 같은 형태로 작성합니다. 이를 통해 TU의 서브타입이면 X, 아니면 Y를 반환합니다.

type IsString<T> = T extends string ? "문자열" : "문자열 아님"

type A = IsString<string>; // 문자열
type B = IsString<number>; // 문자열 아님

🔹 다중 조건 처리

T가 여러 조건 중 하나에 해당하는지 확인하고, 해당하는 타입을 반환하는 예시입니다.

type GetType<T> = 
  T extends number ? "숫자" : 
  T extends string ? "문자열" : 
  "기타";

type X = GetType<number>;  // "숫자"
type Y = GetType<string>;  // "문자열"
type Z = GetType<boolean>; // "기타"

🔹 배열 여부 판별

T가 배열 타입인지 아닌지를 확인하는 예시입니다.

type IsArray<T> = T extends any[] ? "배열" : "아님";

type A = IsArray<number[]>; // "배열"
type B = IsArray<string>;   // "아님"



3️⃣ 타입 추론 infer

조건부 타입 내에서 infer를 사용하면 타입 추론을 자동으로 할 수 있습니다.
즉, T가 특정 타입일 경우 해당 타입을 추론하여 그 타입을 활용할 수 있습니다.

🔹 infer 사용 예시

T extends Promise<infer R>Promise 내부에 있는 타입 R을 추론합니다.

type ResolveType<T> = T extends Promise<infer R> ? R : T;

type A = ResolveType<Promise<string>>;  // string
type B = ResolveType<Promise<number>>;  // number
type C = ResolveType<Promise<boolean>>; // boolean
type D = ResolveType<string>;           // string (그대로 반환)



4️⃣ 연습 문제

🔹 문제 1 : number 타입인지 판별하기

// ✅ 주어진 타입이 숫자 타입(number)이면 "숫자"를, 아니면 "다른 타입"을 반환하는 타입을 작성하세요.
type IsNumber<T> = ???

type A = IsNumber<number>;  // "숫자"
type B = IsNumber<string>;  // "다른 타입"
type C = IsNumber<boolean>; // "다른 타입"
정답 보기 🔍
type IsNumber = T extends number ? "숫자" : "다른 타입"

✔️ 타입 Tnumber라면 "숫자"를 아니면 "다른 타입"을 반환


🔹 문제 2 : 객체 타입에서 선택적 프로퍼티(?)만 추출하기

// ✅ 객체 타입 T에서 선택적 프로퍼티만 추출하는 타입을 구현하세요. 선택적 프로퍼티는 undefined 값을 가질 수 있는 프로퍼티입니다.
type ExtractOptional<T> = ???

type Obj = {
  name: string;
  age?: number;
  isActive?: boolean;
};

type A = ExtractOptional<Obj>;  // { age?: number; isActive?: boolean; }
type B = ExtractOptional<{ name: string; isActive: boolean }>;  // {}
정답 보기 🔍
  type ExtractOptional = {
    [K in keyof T as undefined extends T[K] ? K : never]: T[K];
  };

✔️ K in keyof TT의 모든 키를 순회
✔️ as undefined extends T[K] ? K : never → 선택적 속성만 남김
✔️ 필터링된 키로 새로운 객체 타입을 생성


🔹 문제 3 : 함수 타입에서 반환 타입 추출하기

// ✅ 주어진 함수 타입 `T`에서 반환 타입을 추출하는 타입 `ReturnTypeOf`를 작성하세요.
// 예시: `T`가 `(x: string) => number`라면 반환 타입은 `number`입니다.
type ReturnTypeOf<T> = ???

type A = ReturnTypeOf<(x: string) => number>;  // number
type B = ReturnTypeOf<(a: boolean) => string>; // string
type C = ReturnTypeOf<(x: string, y: number) => void>; // void
type D = ReturnTypeOf<() => boolean>; // boolean
정답 보기 🔍
 type ReturnTypeOf = T extends (...args: any[]) => infer R ? R : never;

✔️ 파라미터는 any[]로 받아 모든 인자 타입을 허용
✔️ T가 함수 타입이라면 infer R로 반환값의 타입을 추론
✔️ 함수 타입이 아니라면 never를 반환